package com.htzg.agentmaindemo;


import com.htzg.agentmaindemo.iface.OpenraspModule;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.web.servlet.ServletComponentScan;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zgb
 */

@Slf4j
//自动扫描并注册带有@ConfigurationProperties注解的类作为SpringBean
@ConfigurationPropertiesScan("com.htzg.agentmaindemo")
//在SpringBootApplication上使用@ServletComponentScan注解后:Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册，无需其他代码
//@ServletComponentScan(basePackages = {"com.audaque.springboot.foshanupload"})//servlet扫描
@ServletComponentScan

//@SpringBootApplication里面有@ComponentScan：告诉Spring从哪里找到bean，包扫描会扫描只要标注了@Controller,@Service,@Repository,@Component这四个注解都会被扫描到容器中。

//如果项目不需要数据库相关信息就排除此类的autoconfig
//@SpringBootApplication可以运行war
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
//把启动类放到同级下或让所有Java类都在启动类的子包下就可以完成基于Java注入bean的方式了
//@SpringBootApplication(scanBasePackages = "com.audaque.springboot.foshanupload.web.demo.controller")
//@SpringBootApplication
public class AgentMainDemoApplication {

    //agent方式2：程序运行中的agent：agentmain
    public static void main(String[] args) {
        SpringApplication.run(AgentMainDemoApplication.class, args).registerShutdownHook();
        String agentJarPath = "";
        List<String> strings = new ArrayList<>();
        for (String arg : args) {
            log.info("arg:" + arg);
            String[] split = arg.split("=");
            if (Objects.equals(split[0], "agentJarPath")) {
                agentJarPath = split[1];
            } else {
                strings.add(arg);
            }
        }
        if (StringUtils.isNotBlank(agentJarPath)) {
            String join = String.join(",", strings);
            try {
                loadAgent(agentJarPath, join);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void loadAgent(String agentJarPath, String options) throws Exception {
        String[] splits = options.split(",");
        String handleSpringBootApplicationClassName = null;
        String handleJarPath = null;
        String openraspYn = null;
        List<String> collect = Arrays.stream(splits).collect(Collectors.toList());
        for (String e : collect) {
            String[] splits1 = e.split("=");
            if (Objects.equals(splits1[0], "handleSpringBootApplicationClassName")) {
                handleSpringBootApplicationClassName = splits1[1];
            } else if (Objects.equals(splits1[0], "handleJarPath")) {
                handleJarPath = splits1[1];
            } else if (Objects.equals(splits1[0], "openraspYn")) {
                openraspYn = splits1[1];
            }
        }
        if (StringUtils.isBlank(handleSpringBootApplicationClassName) && StringUtils.isBlank(handleSpringBootApplicationClassName)) {
            throw new RuntimeException("handleSpringBootApplicationClassName 或 handleJarPath 必填其一");
        }

        // 列出本机已加载的jvm
        List<VirtualMachineDescriptor> list = VirtualMachine.list();
        // 遍历已加载的jvm
        for (VirtualMachineDescriptor v : list) {
            String id = v.id();
            log.info("id:" + id);
            // 打印jvm的 displayName 属性
            String displayName = v.displayName();
            log.info("displayName:" + displayName);
            log.info("handleSpringBootApplicationClassName:" + handleSpringBootApplicationClassName);
            log.info("handleJarPath:" + handleJarPath);

            if (Objects.equals(handleSpringBootApplicationClassName, "org.apache.catalina.startup.Bootstrap")) {
                handleSpringBootApplicationClassName += " start";
            }
            // 如果 displayName 为指定的类
            if (StringUtils.isNotBlank(displayName)
                    &&
                    (
                            (StringUtils.isNotBlank(handleSpringBootApplicationClassName) && displayName.startsWith(handleSpringBootApplicationClassName))
                                    ||
                                    (StringUtils.isNotBlank(handleJarPath) && displayName.startsWith(handleJarPath))
                    )
            ) {
                // 打印pid
                log.info("命中pid:" + id);
                // 将 jvm 虚拟机的 pid 号传入 attach 来进行远程连接，可以自连或连别人
                VirtualMachine vm = VirtualMachine.attach(id);
                if(Objects.equals(openraspYn,"true")){
                    options= OpenraspModule.START_ACTION_INSTALL;
                }
                // 将我们的 agent.jar 发送给虚拟机
                vm.loadAgent(agentJarPath, options);
                // 解除链接
                vm.detach();
            }
        }
    }
}

